import {
  arrayMethods
} from "./arrayObserver"

// 收集的依赖在哪？
function defineReactive(data, key, val) {
  // 存储 依赖
  let dep = []
  Object.defineProperty(data, key, {
    enumerable: true,
    configurable: true,
    get() {
      // 收集依赖
      dep.push(window.target)
      return val
    },
    set(newVal) {
      if (val === newVal) {
        return
      }
      // 循环触发收集到的依赖
      for (let i = 0, len = dep.length; i < len; i++) {
        dep[i](newVal, val)
      }
      val = newVal
    }
  })
}

function remove(arr, item) {
  if (arr.length) {
    const index = arr.indexOf(item)
    if (index > -1) {
      return arr.splice(index, 1)
    }
  }
}
// 定义Dep 类
export class Dep {
  constructor() {
    this.subs = []
  }
  addSub(sub) {
    this.subs.push(sub)
  }
  removeSub(sub) {
    remove(this.subs, sub)
  }
  depdend() {
    if (window.target) {
      this.addSub(window.target)
    }
  }
  notify() {
    const sub = this.subs.slice()
    for (let i = 0; i < sub.length; i++) {
      sub[i].update()
    }
  }
}

// 改造 

function defineReactive2(data, key, val) {
  if (typeof val === 'object') {
    new Observer(val)
  }
  const dep = new Dep()
  Object.defineProperty(data, key, {
    enumerable: true,
    configurable: true,
    get() {
      dep.depdend()
      //这里收集Array的依赖
      return val
    },
    set(newVal) {
      if (newVal === val) {
        return
      }
      val = newVal
      dep.notify()
    }
  })
}

// 改造 3

function defineReactive2(data, key, val) {
  const childOb = observe(val) //修改
  const dep = new Dep()
  Object.defineProperty(data, key, {
    enumerable: true,
    configurable: true,
    get() {
      dep.depdend()
      //这里收集Array的依赖
      if (childOb) {
        childOb.dep.depdend()
      }

      return val
    },
    set(newVal) {
      if (newVal === val) {
        return
      }
      val = newVal
      dep.notify()
    }
  })
}


// class Observer{
//   constructor(value){
//     this.value=value
//     if(Array.isArray(value)){
//       // 覆盖 响应式数组 原型对象
//       value.__proto__=arrayMethods
//     }else{
//       this.walk(value)
//     }
//   }

//   walk(obj){
//     const keys=Object.keys(obj)
//     for(let i=0;i<keys.length;i++){
//       defineReactive2(obj,keys[i],obj[keys[i]])
//     }

//   }
// }


// 不支持 __proto__属性

const hasProto = "__proto__" in {};
// 返回一个由指定对象的所有自身属性的属性名（包括不可枚举属性但不包括 Symbol 值作为名称的属性）组成的数组。
const arrayKeys = Object.getOwnPropertyNames(arrayMethods)

function protoArgument(target, src, keys) {
  target.__proto__ = src
}

function copyArgument(target, src, keys) {
  for (let i = 0, l = keys.length; i < l; i++) {
    const key = keys[i]
    def(target, key, src[key])
  }
}
class Observer {
  constructor(value) {
    this.value = value
    // 数组将收集依赖存放在 Observer中： 在拦截器和 getter中都能接受到
    this.dep = new Dep()
    // 新增 不可枚举的 __ob__属性，其值就是当前的 Observer 实例
    def(val, '__ob__', this)
    
    if (Array.isArray(value)) {
      const argument = hasProto ? protoArgument : copyArgument
      argument(value, arrayMethods, arrayKeys)
    } else {
      this.walk(value)
    }
  }

  walk(obj) {
    const keys = Object.keys(obj)
    for (let i = 0; i < keys.length; i++) {
      defineReactive2(obj, keys[i], obj[keys[i]])
    }

  }
}

// 如果value 是响应式则返回
// 如果不是 则 new
export function observe(value, asRootData) {
  if (!isObject(value)) {
    return
  }
  // instanceof 运算符用来检测 constructor.prototype 是否存在于参数 object 的原型链上。
  // 如果指定的对象自身有指定的属性，则静态方法 Object.hasOwn() 返回 true。如果属性是继承的或者不存在，该方法返回 false。
  if (hasOwn(value, '__ob__') && value instanceof Observer) {
    ob = value.__ob__
  } else {
    ob = new Observer(value)
  }
  return ob
}

function def(obj, key, val, enumerable) {
  Object.defineProperty(obj, key, {
    enumerable: !!enumerable,
    configurable: true,
    writable: true,
    value: val
  })
}

